{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "from darter.file import parse_elf_snapshot, parse_appjit_snapshot"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Loading and parsing the snapshot file\n",
    "\n",
    "Here we open the file to inspect. It actually contains *two* snapshots, one is the common **base** and the other contains the actual **user code**.  \n",
    "`parse_elf_snapshot` extracts the 2 blobs for each of the two snapshots, and parses them.\n",
    "It only returns the second snapshot, which is the interesting one (and contains the base, too).\n",
    "\n",
    "By default we are inspecting an included sample file which results from building the default Flutter app:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": true,
    "jupyter": {
     "outputs_hidden": true
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "------- PARSING VM SNAPSHOT --------\n",
      "\n",
      "[Header]\n",
      "  length = 4733\n",
      "  kind = 2 ('kFullAOT', 'Full + AOT code')\n",
      "\n",
      "[Snapshot header]\n",
      "  version = 'c8562f0ee0ebc38ba217c7955956d1cb'\n",
      "  features = {'product': True, 'use_bare_instructions': True, 'asserts\"': False, 'causal_async_stacks': True, 'bytecode': False, 'arm-eabi': True, 'softfp': True}\n",
      "\n",
      "  base objects: 95\n",
      "  objects: 935\n",
      "  clusters: 5\n",
      "  code order length = 69\n",
      "\n",
      "[002c1094]: INFO: Reading allocation clusters...\n",
      "[002c13a9]: INFO: Reading fill clusters...\n",
      "[002c2215]: INFO: Reading roots...\n",
      "[002c2281]: INFO: Snapshot parsed.\n",
      "\n",
      "------- PARSING ISOLATE SNAPSHOT --------\n",
      "\n",
      "[Header]\n",
      "  length = 836159\n",
      "  kind = 2 ('kFullAOT', 'Full + AOT code')\n",
      "\n",
      "[Snapshot header]\n",
      "  version = 'c8562f0ee0ebc38ba217c7955956d1cb'\n",
      "  features = {'product': True, 'use_bare_instructions': True, 'asserts\"': False, 'causal_async_stacks': True, 'bytecode': False, 'arm-eabi': True, 'softfp': True}\n",
      "\n",
      "  base objects: 935\n",
      "  objects: 74247\n",
      "  clusters: 222\n",
      "  code order length = 7228\n",
      "\n",
      "[002c7098]: INFO: Reading allocation clusters...\n",
      "[002d8228]: INFO: Reading fill clusters...\n",
      "[00393161]: INFO: Reading roots...\n",
      "[00393243]: INFO: Snapshot parsed.\n"
     ]
    }
   ],
   "source": [
    "s = parse_elf_snapshot('samples/arm-app.so')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "If your snapshot is AppJIT instead of AppAOT, you can use `parse_appjit_snapshot`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "collapsed": true,
    "jupyter": {
     "outputs_hidden": true
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Blob lengths: (0, 0, 17599488, 6822944)\n",
      "No base snapshot, skipping base snapshot parsing...\n",
      "\n",
      "------- PARSING ISOLATE SNAPSHOT --------\n",
      "\n",
      "[Header]\n",
      "  length = 12708502\n",
      "  kind = 1 ('kFullJIT', 'Full + JIT code')\n",
      "\n",
      "[Snapshot header]\n",
      "  version = 'c8562f0ee0ebc38ba217c7955956d1cb'\n",
      "  features = {'release': True, 'use_bare_instructions': True, 'asserts\"': False, 'use_field_guards\"': True, 'use_osr\"': True, 'causal_async_stacks': True, 'bytecode': False, 'x64-sysv': True}\n",
      "\n",
      "  base objects: 934\n",
      "  objects: 297885\n",
      "  clusters: 160\n",
      "  code order length = 0\n",
      "\n",
      "[000010ad]: NOTICE: Snapshot expected 934 base objects, but the provided base has 95\n",
      "[000010ad]: INFO: Reading allocation clusters...\n",
      "[0003c3f2]: INFO: Reading fill clusters...\n",
      "[00c1f990]: INFO: Reading roots...\n",
      "[00c1fa9a]: INFO: Snapshot parsed.\n"
     ]
    }
   ],
   "source": [
    "s = parse_appjit_snapshot('samples/appjit.snapshot')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "If the parsing was successful, then you are good to go!"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Navigating the snapshot data\n",
    "\n",
    "A Dart snapshot is a collection of objects. Each object is assigned a unique **ref number** starting with 1 (ref 0 is invalid).  \n",
    "To access an object by its ref number, use `refs`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Class('package:myapp/main.dart', 'MyApp')->2436"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "s.refs[2436]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can see that object 2436 is a **Class**. Its representation prints some of its fields (library and name), but we can access them all through its *data dictionary*:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'predefined': False,\n",
       " 'name': 'MyApp'->71516,\n",
       " 'user_name': <base>null,\n",
       " 'functions': Array(1)->63064,\n",
       " 'functions_hash_table': <base>null,\n",
       " 'fields': <base Array><empty_array>,\n",
       " 'offset_in_words_to_field': <base>null,\n",
       " 'interfaces': Array(0)->63063,\n",
       " 'script': Script('package:myapp/main.dart')->11481,\n",
       " 'library': Library('package:myapp/main.dart')->11847,\n",
       " 'type_parameters': <base>null,\n",
       " 'super_type': Type(Class('package:flutter/src/widgets/framework.dart', 'StatelessWidget')->1249)->48108,\n",
       " 'signature_function': <base>null,\n",
       " 'constants': <base Array><empty_array>,\n",
       " 'declaration_type': Type(Class('package:myapp/main.dart', 'MyApp')->2436)->48663,\n",
       " 'invocation_dispatcher_cache': <base Array><empty_array>,\n",
       " 'allocation_stub': Code->18051,\n",
       " 'cid': 981,\n",
       " 'instance_size_in_words': 2,\n",
       " 'next_field_offset_in_words': 2,\n",
       " 'type_arguments_field_offset_in_words': -1,\n",
       " 'num_type_arguments': 0,\n",
       " 'num_native_fields': 64,\n",
       " 'token_pos': 74,\n",
       " 'end_token_pos': 954,\n",
       " 'state_bits': 1097768}"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "s.refs[2436].x"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "As you can see some of the fields point to other objects, so we can go on and inspect them too:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Type(Class('package:flutter/src/widgets/framework.dart', 'StatelessWidget')->1249)->48108"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "s.refs[2436].x['super_type']"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`snapshot.getrefs(...)` lists all objects of a certain type:\n",
    "\n",
    "~~~ python\n",
    "for obj in s.getrefs('Function'):\n",
    "    # TODO\n",
    "~~~\n",
    "\n",
    "To iterate over all objects of a snapshot (including its base):\n",
    "\n",
    "~~~ python\n",
    "for ref in range(1, s.refs['next']):\n",
    "    obj = s.refs[ref]\n",
    "    # TODO\n",
    "~~~"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Arrays\n",
    "\n",
    "**Array** or **ImmutableArray** objects have one or more object items, which can be accessed through the `value` field in its data dictionary.  \n",
    "However, it's better to just call `obj.values()`, which also handles the special case of an empty array:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Array(7)->63969\n",
      "[<base>null, <base>null, Class('package:myapp/main.dart', '_MyHomePageState@465264790')->2061, Class('package:myapp/main.dart', 'MyApp')->2436, Function('main', 0)->9741, Class('package:myapp/main.dart', 'MyHomePage')->2099, Mint(4)->49841]\n"
     ]
    }
   ],
   "source": [
    "obj = s.refs[2436].x['library'].x['dictionary']\n",
    "print(obj)\n",
    "print(obj.values())  # or obj.x['value']"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**GrowableObjectArray** objects have a *backing array* and a length:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "GrowableObjectArray(1, Array(3)->63967)->54880"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "s.refs[2436].x['library'].x['owned_scripts']"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`values()` works on these objects too:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[Script('package:myapp/main.dart')->11481]"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "s.refs[2436].x['library'].x['owned_scripts'].values()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Strings\n",
    "\n",
    "**OneByteString** and **TwoByteString** objects hold a string, which is printed in its representation:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'Flutter Demo Home Page'->69306"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "s.refs[69306]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You can access the string through the `value` field in its data dictionary:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'Flutter Demo Home Page'"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "s.refs[69306].x['value']"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Snapshots have a `strings` dictionary, which allows you to access the object for a certain string:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'Flutter Demo Home Page'->69306"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "s.strings['Flutter Demo Home Page']"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Backreferences\n",
    "\n",
    "So far, we've seen how an object references other objects through its data dictionary:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Class('package:myapp/main.dart', 'MyApp')->2436\n",
      "Script('package:myapp/main.dart')->11481\n"
     ]
    }
   ],
   "source": [
    "print(s.refs[2436])\n",
    "print(s.refs[2436].x['script'])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "But we can look up *where is an object referenced from*, through its `src` attribute:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Referenced from: (Class('package:myapp/main.dart', '_MyHomePageState@465264790')->2061, 'script')\n",
      "Referenced from: (Class('package:myapp/main.dart', 'MyHomePage')->2099, 'script')\n",
      "Referenced from: (Class('package:myapp/main.dart', 'MyApp')->2436, 'script')\n",
      "Referenced from: (Class('package:myapp/main.dart', '::')->2565, 'script')\n",
      "Referenced from: (Array(3)->63967, 'value', 0)\n"
     ]
    }
   ],
   "source": [
    "for backref in s.refs[2436].x['script'].src:\n",
    "    print('Referenced from:', backref)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Each item of `src` is a tuple; its first item is the referencing object, and the next item(s) describe the field where it's referenced.  \n",
    "We can see that 4 classes reference the object with its `script` field, and an array contains the object in its first item.\n",
    "\n",
    "This is pretty useful when combined with `snapshot.strings`. To find the `MyApp` class, we can get that string and look at its `src`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[(Class('package:myapp/main.dart', 'MyApp')->2436, 'name'),\n",
       " (Array(16386)->64169, 'value', 14917)]"
      ]
     },
     "execution_count": 33,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "s.strings['MyApp'].src"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "And there it is, in the first tuple."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Other operations\n",
    "\n",
    "Use `obj.is_cid(...)` to check that an object is of certain kind, and `obj.ref` to get its reference number:\n",
    "\n",
    "~~~ python\n",
    "s.refs[2436].is_cid('Class')  # True\n",
    "s.refs[2436].ref  # 2436\n",
    "~~~"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Calling `obj.describe()` returns its representation, plus (for code-related objects) some context describing its location in the code:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Code->18052\n",
      "Code->18052{ Function('build', 2)->9029 Class('package:myapp/main.dart', 'MyApp')->2436 }\n"
     ]
    }
   ],
   "source": [
    "print(s.refs[18052])\n",
    "print(s.refs[18052].describe())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### The root object\n",
    "\n",
    "There's one more object, the root object, which doesn't have a ref number and can be accessed through `snapshot.refs['root']`. It has things like the global object pool, the symbol table, core classes, and some stubs (Code objects) for low-level tasks:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'object_class': Class('Object')->1028,\n",
       " 'object_type': Type(Class('Object')->1028)->48997,\n",
       " 'null_class': Class('Null')->1027,\n",
       " 'null_type': Type(Class('Null')->1027)->48996,\n",
       " 'function_type': Type(Class('Function')->1029)->48995,\n",
       " 'type_type': Type(Class('Type')->2591)->48994,\n",
       " 'closure_class': Class('_Closure@0150898')->1026,\n",
       " 'number_type': Type(Class('num')->1007)->48993,\n",
       " 'int_type': Type(Class('int')->1832)->48992,\n",
       " 'integer_implementation_class': Class('_IntegerImplementation@0150898')->1025,\n",
       " 'int64_type': <base>null,\n",
       " 'smi_class': Class('_Smi@0150898')->1024,\n",
       " 'smi_type': Type(Class('_Smi@0150898')->1024)->48991,\n",
       " 'mint_class': Class('_Mint@0150898')->1023,\n",
       " 'mint_type': Type(Class('_Mint@0150898')->1023)->48990,\n",
       " 'double_class': Class('_Double@0150898')->1022,\n",
       " 'double_type': Type(Class('double')->2588)->48989,\n",
       " 'float32x4_type': Type(Class('dart:typed_data', 'Float32x4')->2553)->48988,\n",
       " 'int32x4_type': Type(Class('dart:typed_data', 'Int32x4')->2555)->48987,\n",
       " 'float64x2_type': Type(Class('dart:typed_data', 'Float64x2')->2549)->48986,\n",
       " 'string_type': Type(Class('String')->2482)->48985,\n",
       " 'type_argument_int': TypeArguments->46641,\n",
       " 'type_argument_double': TypeArguments->46640,\n",
       " 'type_argument_string': TypeArguments->46639,\n",
       " 'type_argument_string_dynamic': TypeArguments->46638,\n",
       " 'type_argument_string_string': TypeArguments->46637,\n",
       " 'compiletime_error_class': <base>null,\n",
       " 'pragma_class': <base>null,\n",
       " 'pragma_name': <base>null,\n",
       " 'pragma_options': <base>null,\n",
       " 'future_class': <base>null,\n",
       " 'completer_class': <base>null,\n",
       " 'symbol_class': <base>null,\n",
       " 'one_byte_string_class': Class('_OneByteString@0150898')->1021,\n",
       " 'two_byte_string_class': Class('_TwoByteString@0150898')->1020,\n",
       " 'external_one_byte_string_class': Class('_ExternalOneByteString@0150898')->1019,\n",
       " 'external_two_byte_string_class': Class('_ExternalTwoByteString@0150898')->1018,\n",
       " 'bool_type': Type(Class('bool')->1017)->48984,\n",
       " 'bool_class': Class('bool')->1017,\n",
       " 'array_class': Class('_List@0150898')->1016,\n",
       " 'array_type': Type(Class('_List@0150898')->1016)->48983,\n",
       " 'immutable_array_class': Class('_ImmutableList@0150898')->1015,\n",
       " 'growable_object_array_class': Class('_GrowableList@0150898')->1014,\n",
       " 'linked_hash_map_class': Class('dart:collection', '_InternalLinkedHashMap@3220832')->1013,\n",
       " 'linked_hash_set_class': Class('dart:collection', '_CompactLinkedHashSet@3220832')->2602,\n",
       " 'float32x4_class': Class('dart:typed_data', '_Float32x4@6027147')->1012,\n",
       " 'int32x4_class': Class('dart:typed_data', '_Int32x4@6027147')->1011,\n",
       " 'float64x2_class': Class('dart:typed_data', '_Float64x2@6027147')->1010,\n",
       " 'error_class': <base>null,\n",
       " 'weak_property_class': Class('_WeakProperty@0150898')->1009,\n",
       " 'symbol_table': Array(16386)->64169,\n",
       " 'canonical_types': Array(4098)->64148,\n",
       " 'canonical_type_arguments': Array(1026)->64147,\n",
       " 'async_library': Library('dart:async')->11859,\n",
       " 'builtin_library': <base>null,\n",
       " 'core_library': Library('dart:core')->11858,\n",
       " 'collection_library': Library('dart:collection')->11857,\n",
       " 'convert_library': Library('dart:convert')->11856,\n",
       " 'developer_library': Library('dart:developer')->11855,\n",
       " 'ffi_library': Library('dart:ffi')->11854,\n",
       " '_internal_library': Library('dart:_internal')->11853,\n",
       " 'isolate_library': Library('dart:isolate')->11852,\n",
       " 'math_library': Library('dart:math')->11851,\n",
       " 'mirrors_library': Library('dart:mirrors')->11850,\n",
       " 'native_wrappers_library': Library('dart:nativewrappers')->11849,\n",
       " 'profiler_library': Library('dart:profiler')->11848,\n",
       " 'root_library': Library('package:myapp/main.dart')->11847,\n",
       " 'typed_data_library': Library('dart:typed_data')->11846,\n",
       " '_vmservice_library': Library('dart:_vmservice')->11845,\n",
       " 'libraries': GrowableObjectArray(235, Array(255)->63758)->54877,\n",
       " 'libraries_map': Array(1026)->63683,\n",
       " 'closure_functions': GrowableObjectArray(388, Array(511)->63682)->54862,\n",
       " 'pending_classes': GrowableObjectArray(0, <base Array><empty_array>)->54861,\n",
       " 'pending_unevaluated_const_fields': <base>null,\n",
       " 'pending_deferred_loads': GrowableObjectArray(0, <base Array><empty_array>)->54860,\n",
       " 'resume_capabilities': GrowableObjectArray(0, <base Array><empty_array>)->54859,\n",
       " 'exit_listeners': GrowableObjectArray(0, <base Array><empty_array>)->54858,\n",
       " 'error_listeners': GrowableObjectArray(0, <base Array><empty_array>)->54857,\n",
       " 'stack_overflow': Instance(Class('StackOverflowError')->2517)->74213,\n",
       " 'out_of_memory': Instance(Class('OutOfMemoryError')->2516)->74214,\n",
       " 'preallocated_unhandled_exception': UnhandledException->45521,\n",
       " 'preallocated_stack_trace': StackTrace->54893,\n",
       " 'lookup_port_handler': <base>null,\n",
       " 'handle_message_function': <base>null,\n",
       " 'growable_list_factory': <base>null,\n",
       " 'simple_instance_of_function': <base>null,\n",
       " 'simple_instance_of_true_function': <base>null,\n",
       " 'simple_instance_of_false_function': <base>null,\n",
       " 'async_clear_thread_stack_trace': Function('_clearAsyncThreadStackTrace@8048458', 0)->9573,\n",
       " 'async_set_thread_stack_trace': <base>null,\n",
       " 'async_star_move_next_helper': <base>null,\n",
       " 'complete_on_async_return': <base>null,\n",
       " 'async_star_stream_controller': <base>null,\n",
       " 'global_object_pool': ObjectPool->19088,\n",
       " 'library_load_error_table': <base>null,\n",
       " 'unique_dynamic_targets': <base>null,\n",
       " 'megamorphic_cache_table': GrowableObjectArray(8, Array(15)->54895)->54650,\n",
       " 'build_method_extractor_code': Code->11867,\n",
       " 'null_error_stub_with_fpu_regs_stub': Code->11866,\n",
       " 'null_error_stub_without_fpu_regs_stub': Code->11865,\n",
       " 'stack_overflow_stub_with_fpu_regs_stub': Code->11864,\n",
       " 'stack_overflow_stub_without_fpu_regs_stub': Code->11863,\n",
       " 'write_barrier_wrappers_stub': Code->11862,\n",
       " 'array_write_barrier_stub': Code->11861,\n",
       " 'megamorphic_miss_code': Code->11860,\n",
       " 'megamorphic_miss_function': Function('megamorphic_miss', 0)->2861}"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "s.refs['root'].x"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Native analysis\n",
    "\n",
    "If we look at the `Flutter Demo Home Page` string, the only objects that reference it are the `global_object_pool` and the `symbol_table`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[(ObjectPool->19088, 'entries', 9188, 'raw_obj'), (Array(16386)->64169, 'value', 3064)]\n"
     ]
    }
   ],
   "source": [
    "src = s.strings['Flutter Demo Home Page'].src\n",
    "print(src)\n",
    "assert src[0][0] == s.refs['root'].x['global_object_pool']\n",
    "assert src[1][0] == s.refs['root'].x['symbol_table']"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "It's used in the `MyApp.build` function, but since this reference is only in the assembled instructions, we don't know about it.  \n",
    "That's what the `darter.asm` module is for. We use the `populate_native_references` method to analyze the instructions:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Starting analysis...\n",
      "Done in 2.83s, processing results\n"
     ]
    }
   ],
   "source": [
    "from darter.asm.base import populate_native_references\n",
    "populate_native_references(s)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "And this populates an `nsrc` field on every object. This field tells us where it's used in native code:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[(Code->18052, 2440608, 'load', 'ip')]"
      ]
     },
     "execution_count": 40,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "s.strings['Flutter Demo Home Page'].nsrc"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "And if we look more closely at that `Code` object..."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "\"Code->18052{ Function('build', 2)->9029 Class('package:myapp/main.dart', 'MyApp')->2436 }\""
      ]
     },
     "execution_count": 41,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "s.strings['Flutter Demo Home Page'].nsrc[0][0].describe()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We see it's the `build` function that we were expecting. The format of the tuples in `nsrc` is `(code object, instruction address, kind of reference, ...)`."
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
